﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HundredMilesSoftware.UltraID3Lib;

namespace HebrewID3Fix
{
	public class CHebrewMP3Fixer
	{
		Encoding m_oCorrectEncoding;
		
		public CHebrewMP3Fixer()
		{
			m_oCorrectEncoding = Encoding.GetEncoding(1255);
		}

		public string FixHebrewString(string a_sString)
		{
			byte[] l_oUnicode = Encoding.Unicode.GetBytes(a_sString);
			byte[] l_oString = new byte[l_oUnicode.Length / 2];

			// Remove every other byte
			for (int i = 0; i < l_oUnicode.Length; i += 2)

				l_oString[i / 2] = l_oUnicode[i];

			string l_sString = m_oCorrectEncoding.GetString(l_oString);
			return l_sString;
		}

		private bool IsStringInEnglish(string a_sString)
		{
			const string Numeric = "0123456789";
			const string Alpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
			const string Punctuation = " .,-=+()[]{}¬/'";
			const string Special = "\"\\\t\r\n";
			const string Lookup = Numeric + Alpha + Punctuation + Special;

			for (int i = 0; i < a_sString.Length; i++)
			{
				if (!Lookup.Contains(a_sString[i].ToString()))
				{
					return false;
				}
			}

			return true;
		}

		public bool StringDamagedUnicodeWise(string a_sString)
		{
			if (a_sString.Length == 0)
				return false;
			if (IsStringInEnglish(a_sString))
				return false;

			byte[] l_abUnicode = Encoding.Unicode.GetBytes(a_sString);

			for (int i = 1; i < l_abUnicode.Length; i += 2)
			{
				if (l_abUnicode[i] != 0)
					return false;
			}
			return true;
		}

		public bool StringDamagedAsciiWise(string a_sString)
		{
			if (a_sString.Length == 0)
				return false;

			byte[] l_abASCII = m_oCorrectEncoding.GetBytes(a_sString);
			byte l_bCompared = l_abASCII[0];

			for (int i = 1; i < l_abASCII.Length; i++)
			{
				// With damaged strings, this ASCII encoder returns the same value for all charactars (It doesn't know those letters)
				if (l_abASCII[i] != l_bCompared)
				{
					// Although it knows special chars...
					if	((l_abASCII[i] != 0x20) &&
						(l_abASCII[i] != '!') &&
						(l_abASCII[i] != '?') &&
						(l_abASCII[i] != '(') &&
						(l_abASCII[i] != ')') &&
						(l_abASCII[i] != '-') &&
						(l_abASCII[i] != '*') &&
						(l_abASCII[i] != '.') &&
						(l_abASCII[i] != '_'))
						return false;
				}
			}

			return true;
		}

		public bool StringDamaged(string a_sString)
		{
			//return StringDamagedAsciiWise(a_sString);
			return StringDamagedUnicodeWise(a_sString);
		}

		public bool FileDamaged(string a_sPath)
		{
			UltraID3 l_oTag = new UltraID3();
			l_oTag.Read(a_sPath);

			return (StringDamaged(l_oTag.Artist) || StringDamaged(l_oTag.Album) || StringDamaged(l_oTag.Title) || StringDamaged(l_oTag.Genre));
		}

		public void FixFile(string a_sPath)
		{
			UltraID3 l_oTag = new UltraID3();
			l_oTag.Read(a_sPath);
			
			// Set it to save as unicode, so this problem won't return
			l_oTag.ID3v23Tag.Frames.SetTextEncoding(TextEncodingTypes.Unicode);

			try
			{
				if (StringDamaged(l_oTag.Artist))
				{
					l_oTag.Artist = FixHebrewString(l_oTag.Artist);
				}
				if (StringDamaged(l_oTag.Album))
				{
					l_oTag.Album = FixHebrewString(l_oTag.Album);
				}
				if (StringDamaged(l_oTag.Title))
				{
					string l_sTitle = FixHebrewString(l_oTag.Title);
					if (l_sTitle.Length > 30)
					{
						l_oTag.ID3v1Tag.Title = l_sTitle.Substring(0, 30);
						l_oTag.ID3v23Tag.Title = l_sTitle;
					}
					else
					{
						l_oTag.Title = l_sTitle;
					}
				}
				if (StringDamaged(l_oTag.Genre))
				{
					try
					{
						l_oTag.Genre = FixHebrewString(l_oTag.Genre);
					}
					catch (Exception)
					{
						//Genre could cause a lot of problems for IDv1. We don't handle it well yet
					}
				}

				l_oTag.Write();
			}
			catch (MultiExceptionException e)
			{
				throw e.Exceptions[0];
			}
			catch (Exception e)
			{
				throw e;
			}
		}
	}
}
